﻿
using System;
using System.Collections.Generic;
using System.Text;
using Slc.Core.Enums;
namespace Slc.Core.Entity
{
    public delegate OQL OQLChildFunc(OQL parent);
    /// <summary>
    /// 获取OQL缓存的委托函数
    /// </summary>
    /// <param name="paraValueObject">构造OQL对象所需要的参数值的对象，比如一个实体类</param>
    /// <returns>OQL</returns>
    public delegate OQL OQLCacheFunc(object paraValueObject);
    /// <summary>
    /// OQL排序的委托方法，用于指定排序的对象
    /// </summary>
    /// <param name="order">OQL排序对象</param>
    public delegate void OQLOrderAction(OQLOrder order);

    public delegate void OQLOrderAction<T>(OQLOrder order, T para) where T : class;
    /// <summary>
    /// 表名称字段结构。OQL内部使用
    /// </summary>
    /// <summary>
    /// 表名称字段类型。OQL内部使用
    /// </summary>
    public class TableNameField
    {
        /// <summary>
        /// 获取表名称
        /// </summary>
        public string Name
        {
            get
            {
                return Entity.GetTableName();
            }
        }
        /// <summary>
        /// 原始字段名
        /// </summary>
        public string Field;
        /// <summary>
        /// 关联的实体类
        /// </summary>
        public EntityBase Entity;
        /// <summary>
        /// 在一系列字段使用中的索引号
        /// </summary>
        public int Index;
        /// <summary>
        /// 字段对应的值
        /// </summary>
        public object FieldValue;

        private string _sqlFieldName;
        /// <summary>
        /// 在ＳＱＬ语句中使用的字段名
        /// </summary>
        public string SqlFieldName
        {
            get
            {
                if (string.IsNullOrEmpty(_sqlFieldName))
                    return this.Field;
                else
                    return _sqlFieldName;
            }
            set
            {
                _sqlFieldName = value;
            }
        }
    }

    public class OQL : IOQL, IDisposable
    {

        #region :.分页相关
        /// <summary>
        /// 查询前N条记录，目前仅支持Access/SqlServer，其它数据库可以使用Limit(N) 方法替代。
        /// </summary>
        public int TopCount = 0;
        /// <summary>
        /// 是否开启分页功能，如果启用，OQL不能设定“排序”信息，分页标识字段将作为排序字段
        /// </summary>
        public bool PageEnable = false;
        /// <summary>
        /// 分页时候每页的记录大小，默认为10
        /// </summary>
        public int PageSize = 10;
        /// <summary>
        /// 分页时候的当前页码，默认为1
        /// </summary>
        public int PageNumber = 1;
        /// <summary>
        /// 分页时候的记录标识字段，默认为主键字段。不支持多主键。
        /// </summary>
        public string PageField = "";
        /// <summary>
        /// 分页的时候记录按照倒序排序（对Oracle数据库不起效）
        /// </summary>
        public bool PageOrderDesc = true;
        /// <summary>
        /// 分页的时候，记录的总数量，如未设置虚拟为999条。如需准确分页，应设置该值。
        /// </summary>
        public int PageWithAllRecordCount = 999;

        /// <summary>
        /// 是否排除重复记录
        /// </summary>
        public bool Distinct;

        /// <summary>
        /// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用主键作为标识的高速分页方式。
        /// 注：调用该方法不会影响生OQL.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
        /// </summary>
        /// <param name="pageSize">页大小</param>
        /// <returns></returns>
        public OQL Limit(int pageSize)
        {
            this.PageEnable = true;
            this.PageSize = pageSize;
            return this;
        }

        /// <summary>
        /// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用主键作为标识的高速分页方式。
        /// 注：调用该方法不会影响生OQL.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
        /// </summary>
        /// <param name="pageSize">页大小</param>
        /// <param name="pageNumber">页号码</param>
        /// <returns></returns>
        public OQL Limit(int pageSize, int pageNumber)
        {
            this.PageEnable = true;
            this.PageSize = pageSize;
            this.PageNumber = pageNumber;
            return this;
        }

        /// <summary>
        /// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用指定字段作为标识的高速分页方式。
        /// 注：调用该方法不会影响生OQL.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
        /// </summary>
        /// <param name="pageSize">页大小</param>
        /// <param name="pageNumber">页号码</param>
        /// <param name="pageField">要排序的字段</param>
        /// <returns></returns>
        public OQL Limit(int pageSize, int pageNumber, string pageField)
        {
            this.PageEnable = true;
            this.PageSize = pageSize;
            this.PageNumber = pageNumber;
            this.PageField = pageField;
            return this;
        }
        #endregion

        #region :.旧版本保留的变量定义
        /// <summary>
        /// 当前实体类
        /// </summary>
        protected internal EntityBase currEntity;
        /// <summary>
        /// 是否已经发生了连接操作
        /// </summary>
        protected internal bool haveJoinOpt;
        /// <summary>
        /// 是否有排序操作
        /// </summary>
        protected internal bool haveOrderBy;
        /// <summary>
        /// SQL选择的字段
        /// </summary>
        protected internal string sql_fields = string.Empty;
        /// <summary>
        /// 查询对应的表
        /// </summary>
        protected internal string sql_table = string.Empty;
        /// <summary>
        /// 查询条件
        /// </summary>
        protected internal string sql_condition = string.Empty;
        #endregion

        #region :.新增变量定义
        const int OQL_SELECT = 1, OQL_UPDATE = 2, OQL_INSERT = 3, OQL_DELETE = 4, OQL_INSERT_FROM = 5, OQL_UPDATE_SELFT = 6;
        private Dictionary<object, string> dictAliases = null;
        private string mainTableName = "";
        private List<string> selectedFieldNames = new List<string>();
        private List<string> _groupbyFieldNames;
        private string sql_from = string.Empty;//Select时候的表名或者Upate，Insert的前缀语句
        private char updateSelfOptChar;
        private int paraIndex = 0;
        private int optFlag = OQL_SELECT;
        private OQL insertFromOql = null;
        private OQL parentOql = null;
        private int fieldGetingIndex = 0;//字段获取顺序的索引，如果有子查询，那么子查询使用父查询的该索引进行递增
        private SqlServerLock serverLock = SqlServerLock.UNKNOW;
        private bool disposed;//是否已经调用了Dispose方法

        protected internal int GetFieldGettingIndex()
        {
            if (parentOql != null)
                return parentOql.GetFieldGettingIndex();
            return ++fieldGetingIndex;
        }
        /// <summary>
        /// 是否具有子查询
        /// </summary>
        protected internal bool haveChildOql = false;

        /// <summary>
        /// Where之后的OQL字符串
        /// </summary>
        protected internal string oqlString = "";
        /// <summary>
        /// 字段堆栈
        /// </summary>
        protected internal Stack<TableNameField> fieldStack = new Stack<TableNameField>();
        /// <summary>
        /// SQL 函数
        /// </summary>
        protected internal string sqlFunctionString = string.Empty;
        /// <summary>
        /// 分组字段名
        /// </summary>
        protected internal List<string> GroupbyFieldNames
        {
            get
            {
                if (_groupbyFieldNames == null)
                    _groupbyFieldNames = new List<string>();
                return _groupbyFieldNames;
            }
        }
        #endregion

        #region :.旧方法

        private Dictionary<string, TableNameField> _parameters;
        /// <summary>
        /// 获取条件参数
        /// </summary>
        public Dictionary<string, TableNameField> Parameters
        {
            get
            {
                if (_parameters == null)
                    _parameters = new Dictionary<string, TableNameField>();
                return _parameters;
            }
        }
        //private Dictionary<string, object> _parameters;
        ///// <summary>
        ///// 获取条件参数
        ///// </summary>
        //public Dictionary<string, object> Parameters
        //{
        //    get
        //    {
        //        if (_parameters == null)
        //            _parameters = new Dictionary<string, object>();
        //        return _parameters;
        //    }
        //}

        /// <summary>
        /// 实体类映射的类型
        /// </summary>
        public Db_DataType EntityMap
        {
            get;
            protected set;
        }

        /// <summary>
        /// 根据用户自定义的查询（临时视图），从该查询进一步获取指定的记录的查询语句
        /// </summary>
        /// <param name="tempViewSql">作为子表的用户查询（临时视图）</param>
        /// <returns>符合当前限定条件的查询语句</returns>
        public string GetMapSQL(string tempViewSql)
        {
            if (string.IsNullOrEmpty(tempViewSql))
                throw new Exception("用户的子查询不能为空。");
            this.mainTableName = " (" + tempViewSql + " ) tempView ";
            return ToSelectString("");
        }

        /// <summary>
        /// 要初始化的的参数值，用于自定义查询的实体类
        /// </summary>
        public Dictionary<string, object> InitParameters { get; set; }

        #endregion

        #region :.新增非公开方法
        /// <summary>
        /// 获取OQL使用的字段名
        /// </summary>
        /// <param name="tnf"></param>
        /// <returns></returns>
        protected internal string GetOqlFieldName(TableNameField tnf)
        {
            if (dictAliases == null)
                return string.Format(" [{0}]", tnf.Field);
            else
            {
                string aliases = "";
                if (dictAliases.TryGetValue(tnf.Entity, out aliases))
                {
                    return string.Format(" {0}.[{1}]", aliases, tnf.Field);
                }
                else
                {
                    return string.Format(" M.[{0}]", tnf.Field);
                }
            }

        }
        /// <summary>
        /// 获取表的别名
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected internal string GetTableAliases(EntityBase entity)
        {
            string aliases = "";
            if (dictAliases.TryGetValue(entity, out aliases))
                return aliases;
            else
                return "";
        }
        /// <summary>
        /// 从堆栈上取一个以逗号间隔字段名数组字符串
        /// </summary>
        /// <returns></returns>
        protected internal string TakeStackFields()
        {
            string[] fieldNames = new string[fieldStack.Count];
            for (int i = fieldStack.Count - 1; i >= 0; i--)
            {
                TableNameField tnf = fieldStack.Pop();
                fieldNames[i] = GetOqlFieldName(tnf);
            }
            return string.Join(",", fieldNames);
        }
        private TableNameField TackOneParentStackField()
        {
            if (parentOql == null)
                throw new InvalidOperationException("OQL的父对象为空！");
            var tnf = parentOql.TakeOneStackFields();
            string parentField = tnf.SqlFieldName;
            if (parentField.IndexOf('.') == -1)
                tnf.SqlFieldName = "M." + parentField;

            return tnf;
        }
        //private string TackOneParentStackField(out int index)
        //{
        //    if (parentOql == null)
        //        throw new InvalidOperationException("OQL的父对象为空！");
        //    string parentField = parentOql.TakeOneStackFields(out index).Trim();
        //    if (parentField.IndexOf('.') == -1)
        //        parentField = "M." + parentField;
        //    return parentField;
        //}
        /// <summary>
        /// 从堆栈上只取一个字段名
        /// </summary>
        /// <returns></returns>
        protected internal TableNameField TakeOneStackFields()
        {
            if (fieldStack.Count == 0)
            {
                //如果父OQL不为空，则从父对象获取字段堆栈
                if (parentOql != null)
                    return TackOneParentStackField();
                else
                    throw new ArgumentException("OQL 字段堆栈为空！可能为方法参数未曾调用过OQL关联的实体类的属性。");

            }
            TableNameField tnf = fieldStack.Pop();
            tnf.SqlFieldName = GetOqlFieldName(tnf);
            return tnf;
        }
        ///// <summary>
        ///// 从堆栈上只取一个字段名
        ///// </summary>
        ///// <returns></returns>
        //protected internal string TakeOneStackFields()
        //{
        //    if (fieldStack.Count == 0)
        //    {
        //        //如果父OQL不为空，则从父对象获取字段堆栈
        //        int index = 0;
        //        if (parentOql != null)
        //            return TackOneParentStackField(out index);
        //        else
        //            throw new ArgumentException("OQL 字段堆栈为空！可能为方法参数未曾调用过OQL关联的实体类的属性。");

        //    }
        //    TableNameField tnf = fieldStack.Pop();
        //    return GetOqlFieldName(tnf);
        //}
        ///// <summary>
        ///// 从堆栈上取一个字段
        ///// </summary>
        ///// <param name="index">使用的索引号</param>
        ///// <returns></returns>
        //protected internal string TakeOneStackFields(out int index)
        //{
        //    if (fieldStack.Count == 0)
        //    {
        //        //如果父OQL不为空，则从父对象获取字段堆栈
        //        if (parentOql != null)
        //            return TackOneParentStackField(out index);
        //        else
        //            throw new ArgumentException("OQL 字段堆栈为空！可能为方法参数未曾调用过OQL关联的实体类的属性。");

        //    }
        //    TableNameField tnf = fieldStack.Pop();
        //    index = tnf.Index;
        //    return GetOqlFieldName(tnf);
        //}

        ///// <summary>
        ///// 尝试获取另一个堆栈中的字段，仅当堆栈中剩下一个的时候有效
        ///// </summary>
        ///// <returns></returns>
        //protected internal string TryTakeOneStackFields()
        //{
        //    if (fieldStack.Count == 1)
        //    {
        //        TableNameField tnf = fieldStack.Pop();
        //        return GetOqlFieldName(tnf);
        //    }
        //    else
        //    {
        //        if (parentOql != null)
        //        {
        //            int index = 0;
        //            return TackOneParentStackField(out index);
        //        }

        //    }
        //    return "";
        //}

        /// <summary>
        /// 从堆栈上获取2个字段信息，可能只获取到一个字段信息并自动判断字段是左还是右
        /// </summary>
        /// <typeparam name="T">属性字段的类型</typeparam>
        /// <param name="leftParaValue">左边参数的值</param>
        /// <param name="leftField">输出的左字段</param>
        /// <param name="rightField">输出的右字段</param>
        protected internal void TakeTwoStackFields<T>(T leftParaValue, out TableNameField leftField, out TableNameField rightField)
        {
            leftField = null;
            rightField = null;

            int count = fieldStack.Count;
            if (count == 0)
            {
                //在子查询中条件比较左右字段都用父查询的字段，是不合理的
                throw new ArgumentException("OQL 字段堆栈为空！可能原因为方法使用的实体类不是OQL使用的，或者未使用任何实体类属性，或者使用了父查询的OQL的实体类属性。");
            }
            else if (count == 1)
            {
                TableNameField tnf = fieldStack.Pop();
                //string fieldName = GetOqlFieldName(tnf);
                tnf.SqlFieldName = GetOqlFieldName(tnf);
                //如果当前是子查询，还需要检查父查询的字段堆栈
                if (parentOql != null)
                {
                    var tnfParent = TackOneParentStackField();
                    //int parentFieldIndex = tnfParent.Index;
                    //string parentField = tnfParent.SqlFieldName;
                    if (tnf.Index < tnfParent.Index)
                    {
                        leftField = tnf;
                        rightField = tnfParent;
                    }
                    else
                    {
                        rightField = tnf;
                        leftField = tnfParent;
                    }
                }
                else
                {
                    //通过获取的字段名关联的值，来确定参数所在的顺序
                    object Value = tnf.Entity.PropertyList(tnf.Field);
                    if (Value == DBNull.Value) Value = null;
                    if (Value != null)
                    {
                        //实体属性字段已经赋值过或者为string 类型
                        if (object.Equals(leftParaValue, Value))
                            leftField = tnf;
                        else
                            rightField = tnf;

                    }
                    else
                    {
                        //日期类型必须特殊处理，感谢网友 Sharp_C发现此问题
                        if (typeof(T) == typeof(DateTime) && object.Equals(leftParaValue, new DateTime(1900, 1, 1)))
                            leftField = tnf;
                        else if (object.Equals(default(T), leftParaValue))
                            leftField = tnf;
                        else
                            rightField = tnf;
                    }

                }
            }
            else if (count >= 2)
            {
                //必定是连接查询，左右参数都是字段，而不是值
                TableNameField tnf1 = fieldStack.Pop();
                string fieldName1 = GetOqlFieldName(tnf1);
                tnf1.SqlFieldName = fieldName1;

                TableNameField tnf2 = fieldStack.Pop();
                string fieldName2 = GetOqlFieldName(tnf2);
                tnf2.SqlFieldName = fieldName2;
                //正常情况应该是 tnf1.Index > tnf2.Index
                leftField = tnf2;
                rightField = tnf1;

                fieldStack.Clear();
            }
            else
            {
                throw new InvalidOperationException("当前OQL对象的字段堆栈出现了未期望的字段数量：" + count);

            }

        }
        /// <summary>
        /// 使用当前参数值，创建一个参数名，并将参数的值放到当前对象的参数字典中去
        /// </summary>
        /// <param name="Value"></param>
        /// <returns></returns>
        protected internal string CreateParameter(TableNameField Value)
        {
            string paraName = "@P" + paraIndex++;
            Parameters.Add(paraName, Value);
            return paraName;
        }
        protected internal string CreateParameter(TableNameField field, object Value)
        {
            TableNameField tnf = new TableNameField();
            if (field != null)
            {
                tnf.Entity = field.Entity;
                tnf.Field = field.Field;
                tnf.Index = field.Index;
                tnf.SqlFieldName = field.SqlFieldName;
            }
            tnf.FieldValue = Value;
            return CreateParameter(tnf);
        }
        /// <summary>
        /// 获取当前OQL对象正在使用的实体类
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        protected internal T GetUsedEntity<T>() where T : class
        {
            if (this.currEntity is T)
                return this.currEntity as T;
            if (dictAliases != null)
            {
                foreach (object key in dictAliases.Keys)
                {
                    if (key is T)
                        return key as T;
                }
            }
            return null;
        }

        void e_PropertyGetting(object sender, PropertyGettingEventArgs e)
        {
            TableNameField tnf = new TableNameField()
            {
                Field = e.PropertyName,
                Entity = (EntityBase)sender,
                Index = this.GetFieldGettingIndex()
            };

            fieldStack.Push(tnf);
        }

        private JoinEntity Join(EntityBase entity, string joinTypeString)
        {
            if (dictAliases == null)
                dictAliases = new Dictionary<object, string>();
            dictAliases.Add(entity, "T" + dictAliases.Count);
            haveJoinOpt = true;
            entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
            JoinEntity je = new JoinEntity(this, entity, joinTypeString);

            return je;
        }

        #endregion

        #region :.OQL CRUD 方法
        /// <summary>
        /// 选取要调用的实体类属性字段。该方法可以在OQL实例对象上多次调用
        /// </summary>
        /// <param name="fields"></param>
        /// <returns></returns>
        public OQL1 Select(params object[] fields)
        {
            if (disposed)
                throw new Exception("当前OQL对象已经执行过数据查询，不能再次调用本方法。在执行查询前是可以再次调用本方法的。");
            //防止在调用本方法之前访问关联的实体类属性带来的问题。            
            if (fields.Length > 0)
            {
                int count = fieldStack.Count;
                if (count > fields.Length) //防止才执行本方法前访问了实体类的属性
                    count = fields.Length;
                for (int i = 0; i < count; i++)
                {
                    TableNameField tnf = fieldStack.Pop();
                    selectedFieldNames.Add(string.Format("\r\n    {0}", GetOqlFieldName(tnf)));
                }
                SelectStar = false;
            }
            else
            {
                SelectStar = true;
            }
            fieldStack.Clear();
            selectedFieldNames.Reverse();//恢复正常的字段选取顺序
            return new OQL1(this);
        }

        /// <summary>
        /// 使用是否排除重复记录的方式，来选取实体对象的属性
        /// </summary>
        /// <param name="distinct"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public OQL1 Select(bool distinct, params object[] fields)
        {
            #region :.更新如果查询首字段为bool类型的问题
            int count = fieldStack.Count;
            if (count == fields.Length + 1)
            {
                object[] newFields = new object[count];
                for (int i = 1; i < count; i++)
                    newFields[i] = fields[i - 1];
                newFields[0] = false;
                return Select(newFields);
            }
            #endregion
            this.Distinct = distinct;
            return Select(fields);
        }

        private string PreUpdate()
        {
            string sqlUpdate = "UPDATE " + mainTableName + " SET ";
            string[] updateFieldsString = new string[selectedFieldNames.Count];
            //先将Where条件的参数保存起来
            Dictionary<string, TableNameField> paraTemp = new Dictionary<string, TableNameField>();
            foreach (string key in this.Parameters.Keys)
                paraTemp.Add(key, this.Parameters[key]);
            this.Parameters.Clear();
            //
            for (int i = 0; i < selectedFieldNames.Count; i++)
            {
                int a = selectedFieldNames[i].IndexOf('[');
                int b = selectedFieldNames[i].IndexOf(']');
                string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
                updateFieldsString[i] = selectedFieldNames[i];
                object Value = currEntity.PropertyList(realField);

                TableNameField tnf = new TableNameField();
                tnf.Entity = this.currEntity;
                tnf.Field = realField;
                tnf.FieldValue = Value;
                tnf.Index = i;
                string paraName = CreateParameter(tnf);//参数应该在Ｗｈｅｒｅ的参数前面
                updateFieldsString[i] += " = " + paraName;
            }
            sqlUpdate += string.Join(",", updateFieldsString);
            //恢复条件参数
            foreach (string key in paraTemp.Keys)
                this.Parameters.Add(key, paraTemp[key]);

            return sqlUpdate;
        }

        private string PreUpdateSelf()
        {
            string sqlUpdate = "UPDATE " + mainTableName + " SET ";
            string[] updateFieldsString = new string[selectedFieldNames.Count];
            for (int i = 0; i < selectedFieldNames.Count; i++)
            {
                int a = selectedFieldNames[i].IndexOf('[');
                int b = selectedFieldNames[i].IndexOf(']');
                string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
                object Value = currEntity.PropertyList(realField);

                TableNameField tnf = new TableNameField();
                tnf.Entity = this.currEntity;
                tnf.Field = realField;
                tnf.FieldValue = Value;
                tnf.Index = i;
                string paraName = CreateParameter(tnf);
                updateFieldsString[i] = string.Format(" {0} = {1} {2} {3} "
                    , selectedFieldNames[i], selectedFieldNames[i], this.updateSelfOptChar, paraName);
            }
            sqlUpdate += string.Join(",", updateFieldsString);
            return sqlUpdate;
        }

        /// <summary>
        /// 更新实体类的某些属性值，如果未指定条件，则使用主键值为条件。
        /// </summary>
        /// <param name="fields">实体熟悉列表</param>
        /// <returns>条件表达式</returns>
        public OQL1 Update(params object[] fields)
        {
            if (fields.Length == 0)
                throw new ArgumentException("OQL Update 操作必须指定要操作的实体类的属性！");

            optFlag = OQL_UPDATE;
            OQL1 q1 = Select(fields);
            this.sql_from = PreUpdate();
            return q1;
        }

        /// <summary>
        /// 执行自操作的字段更新，比如为某一个数值性字段执行累加
        /// </summary>
        /// <param name="selfOptChar">自操作类型，有+，-，*，/ 四种类型</param>
        /// <param name="fields">字段列表</param>
        /// <returns></returns>
        public OQL1 UpdateSelf(char selfOptChar, params object[] fields)
        {
            if (selfOptChar == '+' || selfOptChar == '-' || selfOptChar == '*' || selfOptChar == '/')
            {
                optFlag = OQL_UPDATE_SELFT;
                updateSelfOptChar = selfOptChar;

                var q1 = Select(fields);
                this.sql_from = PreUpdateSelf();
                return q1;
            }
            throw new Exception("OQL的字段自操作只能是+，-，*，/ 四种类型");
        }

        public OQL Insert(params object[] fields)
        {
            if (fields.Length == 0)
                throw new ArgumentException("OQL Insert 操作必须指定要操作的实体类的属性！");
            optFlag = OQL_INSERT;
            Select(fields);
            return this;
        }

        public OQL InsertFrom(OQL childOql, params object[] targetTableFields)
        {
            if (targetTableFields.Length == 0)
                throw new ArgumentException("OQL Insert 操作必须指定要操作的实体类的属性！");
            optFlag = OQL_INSERT_FROM;
            Select(targetTableFields);
            insertFromOql = childOql;
            return this;
        }

        /// <summary>
        /// 删除实体类，如果未指定条件，则使用主键值为条件。
        /// </summary>
        /// <returns>条件表达式</returns>
        public OQL1 Delete()
        {
            optFlag = OQL_DELETE;
            return new OQL1(this);
        }

        #endregion

        #region :.构造或者获取实例相关

        public OQL End
        {
            get
            {
                return this;
            }
        }

        public OQL(EntityBase e)
        {
            currEntity = e;
            mainTableName = "[" + e.GetTableName() + "] ";
            sql_table = mainTableName;
            EntityMap = e.EntityMap;
            e.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
        }


        public OQL(EntityBase e, params EntityBase[] others)
            : this(e)
        {
            if (dictAliases == null)
                dictAliases = new Dictionary<object, string>();
            foreach (EntityBase entity in others)
            {
                string aliases = "T" + dictAliases.Count;
                dictAliases.Add(entity, aliases);
                entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
                oqlString += string.Format(",[{0}] {1}", entity.GetTableName(), aliases);
            }
        }

        protected internal void AddOtherEntitys(params EntityBase[] others)
        {
            if (dictAliases == null)
                dictAliases = new Dictionary<object, string>();
            foreach (EntityBase entity in others)
            {
                string aliases = "T" + dictAliases.Count;
                dictAliases.Add(entity, aliases);
                entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
            }
        }

        public OQL(OQL parent, EntityBase e)
            : this(e)
        {
            parentOql = parent;
            parent.haveChildOql = true;
        }

        /// <summary>
        /// 以一个实体类实例对象初始化OQL对象。
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        public static OQL From(EntityBase e)
        {
            return new OQL(e);
        }

        public static OQL From(EntityBase e, params EntityBase[] others)
        {
            return new OQL(e, others);
        }

        public static OQL From(OQL parent, EntityBase e)
        {
            return new OQL(parent, e);
        }

        /// <summary>
        /// 直接返回查询所有数据的泛型OQL表达式
        /// <example>
        /// <code>
        /// <![CDATA[
        ///   List<User> users=OQL.From<User>.ToList();
        /// ]]>
        /// </code>
        /// </example>
        /// </summary>
        /// <typeparam name="T">实体类类型</typeparam>
        /// <returns>OQL表达式</returns>
        public static GOQL<T> FromObject<T>() where T : class
        {
            T obj = EntityBuilder.CreateEntity<T>();
            EntityBase eb = obj as EntityBase;
            if (eb == null)
                throw new ArgumentException("类型的实例必须是继承EntityBase的子类！");
            OQL q = OQL.From(eb);

            return new GOQL<T>(q, obj);
        }

        /// <summary>
        /// 直接返回查询所有数据的OQL表达式
        /// <example>
        /// <code>
        /// <![CDATA[
        ///   List<User> users=OQL.From<User>.ToList<User>();
        /// ]]>
        /// </code>
        /// </example>
        /// </summary>
        /// <typeparam name="T">实体类类型</typeparam>
        /// <returns>OQL表达式</returns>
        public static OQL From<T>() where T : EntityBase, new()
        {
            T entity = new T();
            return new OQL(entity);
        }

        //public static GOQL<Entity> FromObject<T, Entity>() 
        //    where T : new() 
        //    where Entity:EntityBase
        //{
        //    T entity = new T();
        //    EntityBase eb = entity as EntityBase;
        //    if (eb == null)
        //        throw new ArgumentException("类型的实例必须是继承EntityBase的子类！");
        //    OQL q = OQL.From(eb);
        //    //return new GOQL<T>(q, entity);
        //    return null;
        //}

        #endregion

        #region :.连接查询
        /// <summary>
        /// 内连接查询
        /// </summary>
        /// <param name="e">要连接的实体对象</param>
        /// <returns>连接对象</returns>
        public JoinEntity Join(EntityBase e)
        {
            return Join(e, "INNER JOIN");
        }

        /// <summary>
        /// 内连接查询
        /// </summary>
        /// <param name="e">要连接的实体对象</param>
        /// <returns>连接对象</returns>
        public JoinEntity InnerJoin(EntityBase e)
        {
            return Join(e, "INNER JOIN");
        }
        /// <summary>
        /// 左连接查询
        /// </summary>
        /// <param name="e">要连接的实体对象</param>
        /// <returns>连接对象</returns>
        public JoinEntity LeftJoin(EntityBase e)
        {
            return Join(e, "LEFT JOIN");
        }
        /// <summary>
        /// 右连接查询
        /// </summary>
        /// <param name="e">要连接的实体对象</param>
        /// <returns>连接对象</returns>
        public JoinEntity RightJoin(EntityBase e)
        {
            return Join(e, "RIGHT JOIN");
        }

        #endregion

        #region :.获取查询字符串 辅助内部方法
        private string ToInsertFromString(string sql)
        {
            Parameters.Clear();
            string sqlTemplate = "INSERT INTO {0}({1}\r\n\t) \r\n{2} ";
            int count = selectedFieldNames.Count;
            string[] insertFieldsString = new string[count];

            for (int i = 0; i < count; i++)
            {
                int a = selectedFieldNames[i].IndexOf('[');
                int b = selectedFieldNames[i].IndexOf(']');
                string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
                insertFieldsString[i] = selectedFieldNames[i];
            }

            sql = string.Format(sqlTemplate, mainTableName
                , string.Join(",", insertFieldsString)
                , insertFromOql);

            foreach (string key in insertFromOql.Parameters.Keys)
            {
                Parameters.Add(key, insertFromOql.Parameters[key]);
            }
            return sql;
        }

        private string ToInsertString(string sql)
        {
            Parameters.Clear();
            string sqlTemplate = "INSERT INTO {0}({1}) \r\nVALUES\r\n    ({2}) ";
            int count = selectedFieldNames.Count;
            string[] insertFieldsString = new string[count];
            string[] valuesString = new string[count];
            for (int i = 0; i < count; i++)
            {
                int a = selectedFieldNames[i].IndexOf('[');
                int b = selectedFieldNames[i].IndexOf(']');
                string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
                insertFieldsString[i] = selectedFieldNames[i];
                object Value = currEntity.PropertyList(realField);

                TableNameField tnf = new TableNameField();
                tnf.Entity = this.currEntity;
                tnf.Field = realField;
                string paraName = CreateParameter(tnf, Value);
                valuesString[i] = paraName;
            }

            sql = string.Format(sqlTemplate, mainTableName
                , string.Join(",", insertFieldsString)
                , string.Join(",", valuesString));
            return sql;
        }

        private string ToUpdateString(string sql)
        {
            //if (selectedFieldNames.Count == 0)
            //    throw new ArgumentException("UPDATE 操作未指定任何要更新的字段！");
            sql = this.sql_from + GetWhereString();
            return sql;
        }

        private string ToSelectString(string sql)
        {
            string sqlVar = "";
            if (this.Distinct)
                sqlVar += " DISTINCT ";
            if (TopCount > 0)
                sqlVar += " TOP " + TopCount + " ";//仅限于SQLSERVER/ACCESS

            #region 校验GROUP BY 子句
            string sqlFunTemp = string.Empty;
            if (sqlFunctionString.Length > 0) //是否有聚合函数
            {
                sqlFunTemp = sqlFunctionString;
                if (selectedFieldNames.Count > 0)
                {
                    //GROUP BY 
                    if (GroupbyFieldNames.Count == 0)
                        throw new FormatException("在SELECT 子句中使用聚合、统计函数，如果同时选取了查询的列，那么SQL必须使用GROUP BY 子句！");
                    sqlFunTemp = "," + sqlFunTemp;
                }
            }
            else
            {
                //没有聚合函数，也得检查选择的字段是否在分组的字段内
                int count = GroupbyFieldNames.Count;
                if (count > 0)
                {
                    if (selectedFieldNames.Count == 0)
                        throw new FormatException("如果使用GROUP BY 子句，那么在SELECT 子句中中必须指明要选取的列！");
                    foreach (string str in selectedFieldNames)
                    {
                        string item = str.Trim();
                        if (!GroupbyFieldNames.Contains(item))
                            throw new FormatException("如果使用GROUP BY 子句，那么在SELECT 子句中查询的列必须也在GROUP BY 子句中出现！错误的列：" + item);
                    }

                }
            }
            #endregion

            sql_fields = string.Join(",", selectedFieldNames.ToArray());

            if (dictAliases != null)//有关联查询
            {
                sql_from = mainTableName + " M ";
                if (sql_fields == "" && sqlFunctionString.Length == 0)
                {
                    if (SelectStar)
                        sql_fields = "*";//网友 大大宝 增加该分支
                    else
                    {
                        sql_fields = "M.*";
                        foreach (string str in dictAliases.Values)
                        {
                            sql_fields += string.Format(",{0}.*", str);
                        }
                    }
                }
            }
            else
            {
                sql_from = mainTableName;
                if (sql_fields == "" && sqlFunctionString.Length == 0)
                {
                    if (SelectStar)
                        sql_fields = "*";
                    else
                        sql_fields = "[" + string.Join("],[", this.currEntity.PropertyNames) + "]";// "*";
                }
                if (haveChildOql)
                    sql_from = mainTableName + " M ";
            }



            sql = string.Format("SELECT {0} {1} {2} \r\nFROM {3} {4} {5} "
                , sqlVar
                , sql_fields
                , sqlFunTemp
                , sql_from
                , serverLock == SqlServerLock.UNKNOW ? "" : "WITH(" + serverLock.ToString() + ") "
                , oqlString);

            if (this.PageEnable)
            {
                if (this.PageField == "" && sql.IndexOf(" order by ", StringComparison.OrdinalIgnoreCase) <= 0)
                {
                    if (this.currEntity.PrimaryKeys == null || this.currEntity.PrimaryKeys.Count == 0)
                        throw new Exception("OQL 分页错误，没有指明分页标识字段，也未给当前实体类设置主键。");
                    this.PageField = this.currEntity.PrimaryKeys[0];
                }
            }
            return sql;
        }

        /// <summary>
        /// 获取条件字符串，如果未限定条件，则使用主键的值
        /// </summary>
        /// <returns></returns>
        private string GetWhereString()
        {
            string whereString = oqlString;
            if (whereString.Length < 8)
            {
                whereString = " Where 1=1 ";

                if (this.currEntity.PrimaryKeys.Count == 0)
                    throw new Exception("未指定操作实体的范围，也未指定实体的主键。");
                foreach (string pk in this.currEntity.PrimaryKeys)
                {
                    TableNameField tnf = new TableNameField();
                    tnf.Entity = this.currEntity;
                    tnf.Field = pk;
                    string paraName = CreateParameter(tnf, currEntity.PropertyList(pk));
                    whereString += " And [" + pk + "] =" + paraName + ",";
                }
                whereString = whereString.TrimEnd(',');
                //去除下一次生成重复的条件
                oqlString = whereString;
            }
            return whereString;
        }

        #endregion

        #region :.其它方法

        private OQLCondition _condtion;
        /// <summary>
        /// 获取当前条件比较对象
        /// </summary>
        public OQLCondition Condition
        {
            get
            {
                if (_condtion == null)
                    _condtion = new OQLCondition(this);
                return _condtion;
            }
        }

        public override string ToString()
        {
            string sql = string.Empty;
            if (optFlag == OQL_SELECT)
            {
                sql = ToSelectString(sql);
            }
            else if (optFlag == OQL_UPDATE || optFlag == OQL_UPDATE_SELFT)
            {
                sql = ToUpdateString(sql);
            }
            else if (optFlag == OQL_DELETE)
            {
                string sqlUpdate = "DELETE FROM " + mainTableName + " ";
                sql = sqlUpdate + GetWhereString();
            }
            else if (optFlag == OQL_INSERT)
            {
                sql = ToInsertString(sql);

            }
            else if (optFlag == OQL_INSERT_FROM)
            {
                sql = ToInsertFromString(sql);

            }

            return sql;
        }

        public string PrintParameterInfo()
        {
            if (Parameters == null || Parameters.Count == 0)
                return "-------No paramter.--------\r\n";
            StringBuilder sb = new StringBuilder();
            foreach (var item in Parameters)
            {
                object fieldValue = item.Value.FieldValue;
                string type = fieldValue == null ? "NULL" : fieldValue.GetType().Name;
                sb.Append(string.Format("  {0}={1} \t Type:{2} \r\n", item.Key, fieldValue, type));
            }
            string paraInfoString = string.Format("--------OQL Parameters information----------\r\n have {0} parameter,detail:\r\n{1}", Parameters.Count, sb);
            return paraInfoString + "------------------End------------------------\r\n";
        }

        /// <summary>
        /// 释放实体类事件挂钩。如果没页手工调用，该方法会在EntityQuery 调用
        /// </summary>
        public void Dispose()
        {
            if (disposed)
                return;
            this.currEntity.PropertyGetting -= new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
            if (this.dictAliases != null)
            {
                foreach (EntityBase item in dictAliases.Keys)
                {
                    item.PropertyGetting -= new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
                }
            }
            disposed = true;
        }
        /// <summary>
        /// 如果未选择任何列，生成的SQL语句Select 后面是否用 * 代替。
        /// 用于不想修改实体类结构但又想增加表字段的情况。
        /// </summary>
        public bool SelectStar { get; set; }
        /// <summary>
        /// 制定实体查询的时候表的锁定类型。仅支持SqlServer。
        /// </summary>
        /// <param name="lockType"></param>
        /// <returns></returns>
        public OQL With(SqlServerLock lockType)
        {
            serverLock = lockType;
            return this;
        }

        public OQL With(string sqlLockType)
        {
            sqlLockType = sqlLockType.ToUpper();
            try
            {
                SqlServerLock lockType = (SqlServerLock)Enum.Parse(typeof(SqlServerLock), sqlLockType);
                serverLock = lockType;
                return this;
            }
            catch (Exception)
            {
                throw new ArgumentException(sqlLockType + " 不是SQLSERVER 要求的锁定类型！请参见SqlServerLock 枚举定义。");
            }
        }

        #endregion
    }
}
